#include "TankStatusFuncs.h"
#include <sys/mman.h> // mmap, munmap, PROT_READ, PROT_WRITE, MAP_SHARED, MAP_FAILED
#include <fcntl.h> // shm_open
#include <sys/stat.h>   // 包含 sleep 函数
#include <cstring>  // memcpy memset() fgets()
#include <cstdlib>  // 包含 std::atoi 函数
#include <string>
#include <memory> 
#define IN
#define OUT
// map内存管理
/*
这些函数属于 POSIX 共享内存 API，定义在 librt 库中。在编译和链接时，需要显式地链接 librt 库。
target_link_libraries(${TagetName} rt)
*/
// #include <sys/mman.h> // mmap, munmap, PROT_READ, PROT_WRITE, MAP_SHARED, MAP_FAILED
// #include <fcntl.h> // shm_open
// #include <unistd.h>
// #include <sys/stat.h>   // 包含 sleep 函数
// #include <cstring>  // memcpy
// #include <cstdlib>  // 包含 std::atoi 函数
// #include <memory>  // std::shared_ptr

TankStatus TankStatusFuncs::real_tank_stat = TankStatus::TANK_UNSET;
std::string TankStatusFuncs::m_shared_mem_name = _mem_name;

bool TankStatusFuncs::OpenSharedMemory(std::shared_ptr<int> OUT fd, const IN std::string & shared_mem_name)
{
    // 尝试打开共享内存对象
    *fd = shm_open(shared_mem_name.c_str(), O_RDWR, 0666);
    if (*fd == -1) {
        LOG(INFO) << "CheckFailedSystemRunStat : OpenSharedMemory failed";
        // perror("shm_open");
        return false; // 返回错误码以便调用者处理
    }
    return true;
}


bool TankStatusFuncs::GetSharedMemoryObjectSize(const std::shared_ptr<int> IN fd, std::shared_ptr<off_t> OUT memSize)
{
    // 读取共享内存大小
    struct stat sb;
    if (fstat(*fd, &sb) == -1) {
        // perror("fstat");
        // exit(EXIT_FAILURE);
        LOG(ERROR) << "GetSharedMemoryObjectSize : get fstat failed";
        return false;
    }
    else
    {
        *memSize = sb.st_size;
    }
    return true;
}


bool TankStatusFuncs::CreateSharedMemory(std::shared_ptr<int> OUT fd , const std::string IN & shared_mem_name)
{
    // 创建并打开共享内存对象
    *fd = shm_open(shared_mem_name.c_str(), O_CREAT | O_RDWR | O_EXCL, 0666);
    // O_RDONLY: 以只读方式打开共享内存对象。
    // O_RDWR: 以读写方式打开共享内存对象。
    // O_CREAT: 如果共享内存对象不存在，则创建它。
    // O_EXCL: 如果指定了 O_CREAT 并且共享内存对象已经存在，则返回错误。
    // O_TRUNC: 如果共享内存对象已经存在，并且以可写方式打开，则将其长度截断为0
    // 0666: 共享内存对象的权限（八进制），表示所有用户可读写。
    if(*fd == -1)
    {
        if(errno == EEXIST)
        {
            shm_unlink(shared_mem_name.c_str());
            *fd = shm_open(shared_mem_name.c_str(), O_CREAT | O_RDWR | O_EXCL, 0666); //重新创建
            return true;
        }
        else
        {
            LOG(ERROR) << "CreateSharedMemory : shm_open failed";
            return false;
        }
        // perror("shm_open");
        // exit(EXIT_FAILURE);
    }
    return true;
}

bool TankStatusFuncs::SetSharedMemoryObjectSize(const std::shared_ptr<int> IN fd , off_t IN mem_size,  const std::string IN & shared_mem_name)
{
    // 设置共享内存对象的大小
    if (ftruncate(*fd, mem_size) == -1) {
        // shm_unlink(shared_mem_name.c_str());
        LOG(ERROR) << "SetSharedMemoryObjectSize : ftruncate failed";
        // perror("ftruncate");
        // exit(EXIT_FAILURE);
        return false;
    }
    return true;
}

bool TankStatusFuncs::MappingSharedMemoryObjects(const std::shared_ptr<int> IN fd , off_t IN mem_size,  const std::string IN & shared_mem_name, void ** OUT ptr)
{
    // 映射共享内存对象
    *ptr = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
    if (*ptr == MAP_FAILED) {
        LOG(ERROR) << "MappingSharedMemoryObjects : mmap failed";
        // perror("mmap");
        // shm_unlink(shared_mem_name.c_str());
        // exit(EXIT_FAILURE);
        return false;
    }
    return true;
}

bool TankStatusFuncs::ReadTankStatusByMem(std::shared_ptr<TankStatus> OUT stat, const std::string IN _shared_mem_name )
{
    // off_t mem_size = sysconf(_SC_PAGE_SIZE) * 2;
    // off_t mem_size = 4; //只需要4Byte -> int
    // std::cout << "mem_Size = " << mem_size << std::endl;
    // 创建智能指针用于保存fd文件描述符
    off_t out_size = sizeof(stat);
    std::shared_ptr<int> fd = std::make_shared<int>(0);

     if (OpenSharedMemory(fd, _shared_mem_name)) // 共享内存已经存在，最起码说明之前已经启动过
    {
        // 获取共享内存对象的大小
        std::shared_ptr<off_t>  _mem_size = std::make_shared<off_t>(0);
        if (!GetSharedMemoryObjectSize(fd,_mem_size) || out_size != *_mem_size) //如果获取不到内存空间大小或者大小错误，说明未初始化嘛
        {
            shm_unlink(_shared_mem_name.c_str()); // 直接删除空间，重新创建完事儿，异常就异常了
            close(*fd);
            return false;
        }
        else // 如果都是正常的
        {
            void * ptr;
            if (!MappingSharedMemoryObjects(fd, out_size, _shared_mem_name, &ptr)) // 映射共享内存地址
            {
                shm_unlink(_shared_mem_name.c_str()); // 已经删除空间，无需删除
                close(*fd);
                return false;
            }
            else
            {
                // 读取共享内存的内容
                *stat = *(TankStatus*)ptr;
                close(*fd);
                return true;
            }
        }
    }
    return false;
}

bool TankStatusFuncs::WriteTankStatusToMem(std::shared_ptr<TankStatus> IN stat, const std::string IN _shared_mem_name)
{
    // 创建智能指针用于保存fd文件描述符
    std::shared_ptr<int> fd = std::make_shared<int>(0);
    if (OpenSharedMemory(fd, _shared_mem_name)) // 共享内存已经存在，最起码说明之前已经启动过
    {
        off_t mem_size = sizeof(stat);
        // 获取共享内存对象的大小
        std::shared_ptr<off_t>  _mem_size = std::make_shared<off_t>(0);
        if (GetSharedMemoryObjectSize(fd,_mem_size) && mem_size == *_mem_size) 
        {
            void * ptr;
            if (MappingSharedMemoryObjects(fd, mem_size, _shared_mem_name, &ptr)) // 映射共享内存地址
            {
                // 写入共享内存的内容
                memcpy(ptr, (void *)(stat.get()), mem_size);  // 使用 memcpy 将值写入共享内存
                close(*fd);
                return true;
            }
            else
            {
                // 异常的话重建共享内存
            }
        }
        else //如果获取不到内存空间大小或者大小错误，说明未初始化嘛
        {
            // 异常的话重建共享内存
        }
    }
    close(*fd);
    return CreateNewSharedMemAndWrite(stat, _shared_mem_name);
}


bool TankStatusFuncs::CreateNewSharedMemAndWrite(std::shared_ptr<TankStatus> IN stat, const std::string IN _shared_mem_name)
{
    std::shared_ptr<int> fd = std::make_shared<int>(0);
    // 执行创建新的文件
    // 创建并打开共享内存对象
    if (CreateSharedMemory(fd, _shared_mem_name) || *fd != -1)//不管返回值，直接创建
    {
        off_t mem_size = sizeof(stat);
        // 设置共享内存对象的大小
        if (!SetSharedMemoryObjectSize(fd, mem_size, _shared_mem_name))
        {
            shm_unlink(_shared_mem_name.c_str()); // 删除共享内存
            LOG(ERROR) << "CreateNewSharedMemAndWrite : shm_unlink shared_mem : " << _shared_mem_name;
        }
        // 映射共享内存对象
        void * ptr;
        if (!MappingSharedMemoryObjects(fd, m_mem_size, _shared_mem_name, &ptr)) // 映射共享内存地址
        {
            shm_unlink(_shared_mem_name.c_str()); // 已经删除空间，无需删除
            LOG(ERROR) << "CreateNewSharedMemAndWrite : shm_unlink shared_mem : " << _shared_mem_name;
        }
        memcpy(ptr, (void *)(stat.get()), mem_size);  // 使用 memcpy 将值写入共享内存
        close(*fd);
        return true;
    }
    if (*fd != -1)
    {
        close(*fd);
    }
    return false;
}



bool TankStatusFuncs::toggleSystemStart(const std::string IN _shared_mem_name)
{
    std::shared_ptr<TankStatus> _stat = std::make_shared<TankStatus>(TankStatus::TANK_UNSET);
    if (!ReadTankStatusByMem(_stat, _shared_mem_name))
    {
        LOG(ERROR) << "__LINE__ : " << __LINE__ << " , "<<  "toggleSystemStart failed! ";
        return false;
    }
    else //读取到了正确的数值
    {
        uint32_t now_stat = static_cast<uint32_t>(*_stat);
        *_stat = (TankStatus) (!(uint32_t)(*_stat));
        LOG(INFO) << "toggleSystemStart : Read StateByMem is : " << now_stat << " , need write is " << int(*_stat);
        return WriteTankStatusToMem(_stat, _shared_mem_name);
    }
}

bool TankStatusFuncs::CheckSystemIsRunning(void)
{
    std::shared_ptr<TankStatus> _stat = std::make_shared<TankStatus>(TankStatus::TANK_UNSET);
    if (ReadTankStatusByMem(_stat, m_shared_mem_name) && *_stat != TankStatus::TANK_UNSET) // 数据有效
    {
       if (*_stat == TankStatus::TANK_ON)
       {
            LOG(INFO) << __LINE__ << "CheckSystemIsRunning : " << " the system is " << " TANK_ON!";
            return true;
       }
       else
       if (*_stat == TankStatus::TANK_OFF)
       {
            LOG(INFO) << __LINE__ << "CheckSystemIsRunning : " << " the system is " << " TANK_OFF!";
            return false;
       }
       else
       {
            LOG(ERROR) << __LINE__ << "CheckSystemIsRunning failed! , the stat is " << (uint32_t) *_stat;
            return false;
       }
    }
    else
    {
        LOG(INFO) << __LINE__ << "CheckSystemIsRunning : " << " the system is " << " INIT!";
        return false;
    }
    
}
